package com.rederxu.request;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;

import com.rederxu.tools.FileUtils;

public class BreakDownload {

	//每个断点5M
	private static final int stepSize = 5 * 1024 * 1024;
	private static final String TAG = "BreakDownload";
	private static final int CODE_INIT = 100;
	private static final int CODE_DOWNLOADING = 101;
	private static final int CODE_OVER = 102;
	private static final int CODE_PREPARED = 103;
	private static final Bundle bundleUrls = new Bundle();
	//利用这个来记录有多少段已经下载完成了，当url对应的值为0时即为全部下载完成
	private static final Bundle bundle = new Bundle();
	
	public static void download(final String path, final String fileUrl,final onBreakDownloadListener l){
		handler.sendEmptyMessage(CODE_INIT);
		if (bundleUrls.getString(fileUrl) != null) {
			Log.e(TAG, "该文件正在下载，当前下载请求已取消：" + fileUrl);
			return;
		}
		bundleUrls.putString(fileUrl, "");
		new Thread(){
			@Override
			public void run() {
				try {
					String newFileUrl = URLEncoder.encode(fileUrl,"utf-8");
					newFileUrl = newFileUrl.replaceAll("\\+", "%20");
					newFileUrl = newFileUrl.replaceAll("%3A", ":").replaceAll("%2F", "/"); 
					URL url = new URL(newFileUrl);
					URLConnection con = url.openConnection();
					int length = con.getContentLength();
					File fileReal = new File(path + FileUtils.getFileName(fileUrl));
					if(fileReal.length() == length){
						bundleUrls.remove(fileUrl);
						sendMessageFileDownloadOver(l,path + FileUtils.getFileName(fileUrl));
						return;
					}
			    	//记录步起点
			    	int stepIndex = 0;
			    	int index = 0;
			    	while(length > 0){
			    		if(length >= stepSize){
			    			stepDownload(path,fileUrl,length,index,stepIndex,stepIndex + stepSize - 1,l);
				    		stepIndex += stepSize;
			    		}else{
			    			stepDownload(path,fileUrl,length,index,stepIndex,stepIndex + length,l);
				    		stepIndex += length;
			    		}
			    		index ++;
			    		length -= stepSize;
			    	}
			    	sendMessageFileDownloadPrepared(l,index);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				super.run();
			}
		}.start();
	}
	
	private static void stepDownload(final String path,final String fileUrl,final int totalLen,final int index,final int begin,final int over,final onBreakDownloadListener l){
		new Thread(){
			@Override
			public void run() {
				try{
					int num = bundle.getInt(fileUrl);
					bundle.putInt(fileUrl, num + 1);
					File f = new File(fileUrl);
					String model = "TEMP_NAME_INDEX";
					String filePathModel = path + f.getName() + "." + model + ".temp";
					String filePath = filePathModel.replaceAll(model, index + "");
					File file = new File(filePath);
					long start = begin;
					if(!file.exists()){
						file.createNewFile();
					}else if(file.length() < over - begin){
						start = begin + file.length();
					}else{
						num = bundle.getInt(fileUrl) - 1;
						bundle.putInt(fileUrl, num);
						return;
					}
					String range = "bytes=" + start + "-" + over;
					String newFileUrl = URLEncoder.encode(fileUrl,"utf-8");
					newFileUrl = newFileUrl.replaceAll("\\+", "%20");
					newFileUrl = newFileUrl.replaceAll("%3A", ":").replaceAll("%2F", "/"); 
					URL url = new URL(newFileUrl);
					URLConnection con = url.openConnection();
					con.setRequestProperty("Range", range);
					InputStream is = con.getInputStream();
					byte[] bs = new byte[1024];
					int len;
					int max = con.getContentLength();
					int progress = 0; 
					OutputStream os = new FileOutputStream(filePath,true);
					while ((len = is.read(bs)) != -1) {
						os.write(bs, 0, len);
						progress += len;
						sendMessageFileDownloading(l, max, progress,index);
					}
					os.close();
					is.close();
					num = bundle.getInt(fileUrl) - 1;
					bundle.putInt(fileUrl, num);
					if(num <= 0){
						//全部下载完成，开始拼装
						bundleUrls.remove(fileUrl);
						File fileReal = new File(path + FileUtils.getFileName(fileUrl));
						if(!fileReal.exists())
							fileReal.createNewFile();
						FileOutputStream fos = new FileOutputStream(fileReal);
						for(int i = 0;;i++){
							filePath = filePathModel.replaceAll(model, i + "");
							f = new File(filePath);
							if(!f.exists()){
								break;
							}else{
								RandomAccessFile ra = new RandomAccessFile(f, "r");
								byte[] buffer = new byte[1024];
								len = 0;
								while ((len = ra.read(buffer)) != -1) {
									fos.write(buffer, 0, len);
								}
								ra.close();
							}
							f.delete();
						}
						fos.close();
						sendMessageFileDownloadOver(l,path + FileUtils.getFileName(fileUrl));
					}
				}catch(Exception e){
					Log.e("fileDownload", e.toString() + "\n正在重试");
					int num = bundle.getInt(fileUrl) - 1;
					bundle.putInt(fileUrl, num);
					stepDownload(path, fileUrl, totalLen, index, begin, over, l);
				}
				super.run();
			}
		}.start();
	}
	
	private static void sendMessageFileDownloadPrepared(onBreakDownloadListener listener,int threadCount){
		Message msg = new Message(); 
		msg.what = CODE_PREPARED;
		msg.obj = listener;
		Bundle bundle = new Bundle();
		bundle.putInt("threadCount", threadCount);
		msg.setData(bundle);
		handler.sendMessage(msg);
	}
	
	private static void sendMessageFileDownloading(onBreakDownloadListener listener,int max,int progress,int index){
		Message msg = new Message();
		msg.what = CODE_DOWNLOADING;
		msg.obj = listener;
		Bundle bundle = new Bundle();
		bundle.putInt("max", max);
		bundle.putInt("progress", progress);
		bundle.putInt("index", index);
		msg.setData(bundle);
		handler.sendMessage(msg);
	}
	
	private static void sendMessageFileDownloadOver(onBreakDownloadListener listener,String filePath){
		Message msg = new Message();
		msg.what = CODE_OVER;
		msg.obj = listener;
		Bundle bundle = new Bundle();
		bundle.putString("filePath", filePath);
		msg.setData(bundle);
		handler.sendMessage(msg);
	}
	
	private static Handler handler = new Handler(){

		@Override
		public void handleMessage(Message msg) {
			switch(msg.what){
			case CODE_INIT:
				break;
			case CODE_PREPARED:
				onBreakDownloadListener listener = (onBreakDownloadListener) msg.obj;
				Bundle bundle = msg.getData();
				if(listener != null){
					listener.onPrepared(bundle.getInt("threadCount"));
				}
				break;
			case CODE_DOWNLOADING:
				listener = (onBreakDownloadListener) msg.obj;
				bundle = msg.getData();
				if(listener != null){
					listener.onDownloading(bundle.getInt("max"), bundle.getInt("progress"), bundle.getInt("index"));
				}
				break;
			case CODE_OVER:
				listener = (onBreakDownloadListener) msg.obj;
				if(listener != null){
					bundle = msg.getData();
					listener.onDownloadOver(bundle.getString("filePath"));
				}
				break;
			}
			super.handleMessage(msg);
		}
		
	};
}
